package onlinebanking.security.probabilistic;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.LinkedList;
import java.util.Random;

public class GMTester {
	public static void main(String arg[]) throws IOException {

		PrintWriter[] printWriters = new PrintWriter[4];

		PrintWriter keyGenerationLog = new PrintWriter(new FileWriter(new File(
				"key generation log.txt")));
		PrintWriter encrpytionLog = new PrintWriter(new FileWriter(new File(
				"encryption log.txt")));
		PrintWriter decryptionLog = new PrintWriter(new FileWriter(new File(
				"decryption log.txt")));
		PrintWriter ratioLog = new PrintWriter(new FileWriter(new File(
				"ratio log.txt")));

		printWriters[0] = keyGenerationLog;
		printWriters[1] = encrpytionLog;
		printWriters[2] = decryptionLog;
		printWriters[3] = ratioLog;

		int sampleSize = 100;

		long startTime;
		long endTime;

		// int bitLength = 1024;

		char[] characterPool = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
				.toCharArray();
		int characterPoolSize = characterPool.length;
		int[] stringLengthArray = { 4, 8, 16, 32, 64, 128, 256 };

		int[] bitLengthArray = { 4, 8, 16, 32, 64, 128, 256, 512, 1024 };

		for (PrintWriter printWriter : printWriters) {
			printWriter.print("bit length->\t");
		}
		for (int i = 0; i < bitLengthArray.length; i++) {
			for (PrintWriter printWriter : printWriters) {
				printWriter.print("\t" + bitLengthArray[i]);
			}
		}
		
		for (PrintWriter printWriter : printWriters) {
			printWriter.println();
		}

		GMKeyGenerator keyGenerator = GMKeyGenerator.getInstance();

		System.out.println("Probabilistic Engine Started");
		Random random = new Random();
		for (int s = 0; s < stringLengthArray.length; s++) {

			System.out.println("Start of test for string length: "
					+ stringLengthArray[s]);

			char[] randomCharacterArray = new char[stringLengthArray[s]];
			for (int index = 0; index < stringLengthArray[s]; index++) {
				randomCharacterArray[index] = characterPool[random
						.nextInt(characterPoolSize)];
			}
			String randomString = new String(randomCharacterArray);

			for (PrintWriter printWriter: printWriters) {
				printWriter.print("string length [" + stringLengthArray[s] + "]:");
			}
			
			for (int i = 0; i < bitLengthArray.length; i++) {

				// for (int j = 0; j < messages.length; j++) {
				System.out.println("Start of test for bit length: "
						+ bitLengthArray[i]);

				long[] keyGenerationTimeSamples = new long[sampleSize];
				long[] encryptionTimeSamples = new long[sampleSize];
				long[] decryptionTimeSamples = new long[sampleSize];

				double keyGenerationTimeAverage;
				double encryptionTimeAverage;
				double decryptionTimeAverage;
				double decryptionEncryptionAverageRatio;
				
				for (int j = 0; j < sampleSize; j++) {

					// --------------------key generation
					startTime = System.currentTimeMillis();
					GMKeyPair gmKeyPair = keyGenerator
							.generateKeyPair(bitLengthArray[i]);
					endTime = System.currentTimeMillis();
					keyGenerationTimeSamples[j] = (endTime - startTime);
					// System.out.println("Key generated in "
					// + keyGenerationTimeSamples[j] + " milliseconds.");

					GMPrivateKey gmPrivateKey = gmKeyPair.getPrivate();
					GMPublicKey gmPublicKey = gmKeyPair.getPublic();

					// --------------------message encryption
					GMEncoder gmEncoder = new GMEncoder(gmPublicKey);
					startTime = System.currentTimeMillis();
					BigInteger test[] = gmEncoder.encrypt(randomString);
					endTime = System.currentTimeMillis();
					encryptionTimeSamples[j] = (endTime - startTime);
					// System.out.println("Message encrypted in "
					// + encryptionTimeSamples[j] + " milliseconds.");

					// --------------------message decryption
					GMDecoder gmDecoder = new GMDecoder(gmPrivateKey);

					startTime = System.currentTimeMillis();
					gmDecoder.decrypt(test);
					endTime = System.currentTimeMillis();
					decryptionTimeSamples[j] = (endTime - startTime);
					// System.out.println("Message decrypted in "
					// + decryptionTimeSamples[j] + " milliseconds.");

				}

				keyGenerationTimeAverage = getAverage(keyGenerationTimeSamples);
				encryptionTimeAverage = getAverage(encryptionTimeSamples);
				decryptionTimeAverage = getAverage(decryptionTimeSamples);
				decryptionEncryptionAverageRatio = decryptionTimeAverage / encryptionTimeAverage;

				System.out.println("Key generation time average: "
						+ keyGenerationTimeAverage + " milliseconds.");
				System.out.println("Encryption time average: "
						+ encryptionTimeAverage + " milliseconds");
				System.out.println("Decryption time average: "
						+ decryptionTimeAverage + " milliseconds");
				System.out.println("Encryption-Decryption average ratio: "
						+ decryptionEncryptionAverageRatio);

				keyGenerationLog.print("\t" + keyGenerationTimeAverage);
				encrpytionLog.print("\t" + encryptionTimeAverage);
				decryptionLog.print("\t" + decryptionTimeAverage);
				ratioLog.print("\t" + decryptionEncryptionAverageRatio);
				
				System.out.println("End of test for bitLength: "
						+ bitLengthArray[i]);
			}
			
			for (PrintWriter printWriter: printWriters) {
				printWriter.println();
			}
		}

		for (PrintWriter printWriter: printWriters) {
			printWriter.close();
		}
	}

	private static double getAverage(long[] sample) {
		long sum = 0;
		long length = sample.length;
		double average;
		for (int i = 0; i < length; i++) {
			sum += sample[i];
		}
		average = (double) sum / (double) length;
		return average;
	}

}
